package cn.lumora.controller;

import cn.dev33.satoken.stp.StpUtil;
import cn.lumora.controller.req.LoginRequest;
import cn.lumora.core.dto.ApiResponse;
import cn.lumora.core.security.rea.RSACipherUtil;
import cn.lumora.core.security.rea.RSAKeyGenerator;
import cn.lumora.core.security.rea.RSAKeyStorageService;
import cn.lumora.core.security.token.TempTokenService;
import cn.lumora.core.util.RedisUtil;
import cn.lumora.factory.LoginStrategyFactory;
import cn.lumora.factory.RegisterStrategyFactory;
import cn.lumora.strategy.LoginStrategy;
import cn.lumora.strategy.RegisterStrategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.security.KeyPair;
import java.util.Base64;

/**
 * 认证控制器
 */
@RestController
@RequestMapping("/auth")
@Slf4j
public class AuthController {


    /**
     * 登录策略工厂
     */
    private final LoginStrategyFactory loginStrategyFactory;

    /**
     * 注册策略工厂
     */
    private final RegisterStrategyFactory registerStrategyFactory;

    /**
     * 临时令牌服务
     */
    private final TempTokenService tempTokenService;

    /**
     * RSA密钥生成器
     */
    private final RSAKeyGenerator rsaKeyGenerator;

    /**
     * RSA密钥存储服务
     */
    private final RSAKeyStorageService rsaKeyStorageService;

    @Autowired
    public AuthController(LoginStrategyFactory loginStrategyFactory, RegisterStrategyFactory registerStrategyFactory, TempTokenService tempTokenService, RSAKeyGenerator rsaKeyGenerator, RSAKeyStorageService rsaKeyStorageService) {
        this.loginStrategyFactory = loginStrategyFactory;
        this.registerStrategyFactory = registerStrategyFactory;
        this.tempTokenService = tempTokenService;
        this.rsaKeyGenerator = rsaKeyGenerator;
        this.rsaKeyStorageService = rsaKeyStorageService;
    }


    /**
     * 登录
     * @param loginRequest 登录请求
     * @return token 令牌
     */
    @RequestMapping(value = "/login")
    public ApiResponse<String> login(@RequestBody @Validated LoginRequest loginRequest) {
        // 使用策略模式登录
        try {
            int loginType = loginRequest.getLoginType();
            LoginStrategy strategy = loginStrategyFactory.getStrategy(loginType);
            String token = strategy.login(loginRequest);
            return ApiResponse.success(token);
        }catch (Exception e){
            return ApiResponse.error(e.getMessage());
        }
    }

    /**
     * 登出
     */
    @RequestMapping("/logout")
    public String logout() {
        return "logout";
    }

    /**
     * 注册
     * @param loginRequest 注册请求
     * @return 注册结果
     */
    @RequestMapping("/register")
    public ApiResponse<String> register(@RequestBody LoginRequest loginRequest) {
        // 使用策略模式注册
        int registerType = loginRequest.getLoginType();
        RegisterStrategy strategy = registerStrategyFactory.getStrategy(registerType);
        return ApiResponse.success(strategy.register(loginRequest));
    }

    /**
     * 发放临时令牌
     * @param username 用户名
     * @return 临时令牌
     */
    @GetMapping("/tempToken")
    public ApiResponse<String> getTempToken(@RequestParam String username) {
        String tempToken = tempTokenService.generateTempToken(username);
        return ApiResponse.success(tempToken);
    }

    /**
     * TODO 生成新的RSA密钥对(测试使用) 报500不影响使用
     */
    @GetMapping("/generateKeyPair")
    public void generateKeyPair() {
        try {
            // 生成新的密钥对
            KeyPair keyPair = rsaKeyGenerator.generateKeyPair();

            // 将密钥对转换为Base64编码的字符串
            String publicKey = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
            String privateKey = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());

            // 存储新密钥
            rsaKeyStorageService.storeKeyPair(publicKey, privateKey);

            log.info("RSA密钥成功轮换");
        } catch (Exception e) {
            log.error("密钥轮换失败,日志信息:{}", e.getMessage());
        }
    }

    /**
     * 加密数据(测试使用)
     * @param data 要加密的数据
     * @return 加密后的数据
     */
    @GetMapping("/encrypt")
    public ApiResponse<String> encrypt(@RequestParam String data) {
        try {
            // 获取当前公钥版本
            Long currentPublicKeyVersion = rsaKeyStorageService.getCurrentPublicKeyVersion();

            // 获取当前公钥
            String publicKey = rsaKeyStorageService.getPublicKey();

            // 使用公钥进行加密
            String encryptedData = RSACipherUtil.encryptWithPublicKey(data, publicKey);
            log.info("数据成功加密,当前公钥版本:{},加密数据:{}", currentPublicKeyVersion, encryptedData);
            return ApiResponse.success(encryptedData);
        }catch (Exception e){
            log.error("加密失败,日志信息:{}", e.getMessage());
            return ApiResponse.error(e.getMessage());
        }
    }

    // 测试redis
    @GetMapping("/redis")
    public String redis() {
       try {
           String TEMP_TOKEN_PREFIX = "temp_token:"; // 临时令牌键前缀
           String key = "temp_token:5714eff3322b4654826372f921be0e7f";
           RedisUtil.del(key);
           return "redis";
       }catch (Exception e){
           throw new RuntimeException(e);
       }
    }

    @GetMapping("/redis2")
    public void redis2() {
        boolean login = StpUtil.isLogin();
        System.out.println(StpUtil.getLoginId());
        System.out.println(login);
    }
}
